package com.knowledgePointsByMyTest.JavaNIO;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.Iterator;

/**
 * @author yulongtian
 * @create 2024-11-04 14:33
 */
public class NIOServer {
    public static void main(String[] args) throws IOException {
        ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
        //设置非阻塞
        serverSocketChannel.configureBlocking(false);
        // 开启端口监听
        serverSocketChannel.socket().bind(new InetSocketAddress(8888));


        Selector selector = Selector.open();

        // 注册
        serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);

        // 开启selector程序检测
        new Thread(new SingReactor(selector)).start();

    }

    static class SingReactor implements Runnable {

        private final Selector selector;

        public SingReactor(Selector selector) {
            this.selector = selector;
        }

        @Override
        public void run() {
            // 开启多路复用程序
            while (true) {
                // 检测
                try {
                    int select = selector.select();
                    Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();
                    while (iterator.hasNext()) {
                        SelectionKey key = iterator.next();
                        iterator.remove();
                        processSelectedKey(key);
                    }
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
        }

        private void processSelectedKey(SelectionKey key) throws IOException {
            if (key.isValid()) {
                // 按照事件类型进行区分
                if (key.isAcceptable()) {
                    // 连接事件
                    ServerSocketChannel serverSocketChannel = (ServerSocketChannel) key.channel();
                    SocketChannel socketChannel = serverSocketChannel.accept();
                    socketChannel.configureBlocking(false);
                    // 注册
                    socketChannel.register(selector, SelectionKey.OP_READ);
                }
                if (key.isReadable()) {
                    //有数据过来
                    SocketChannel socketChannel = (SocketChannel) key.channel();
                    ByteBuffer allocate = ByteBuffer.allocate(1024);
                    socketChannel.read(allocate);

                    //应用程序从buffer中拿到数据
                    allocate.flip();

                    byte[] bytes = new byte[allocate.remaining()];
                    allocate.get(bytes);
                    String msg = new String(bytes, Charset.defaultCharset());
                    System.out.println("收到了来自客户端的数据:" + msg);

                    // 业务操作


                    // 完成业务操作，向客户端写点数据
                    allocate.clear();
                    allocate.put("hello nio client, i am nio server".getBytes(StandardCharsets.UTF_8));
                    allocate.flip();
                    socketChannel.write(allocate);
                }
            }
        }
    }

}
